#![no_std]
#![no_main]
extern crate alloc;

mod vga_buffer;

use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::vec;
use alloc::vec::Vec;
use core::fmt::Write;
use core::panic::PanicInfo;
use bootloader::{entry_point, BootInfo};
use x86_64::structures::paging::{Page, PageTable, Translate};
use x86_64::VirtAddr;
use blog_os::{allocator, memory};
use blog_os::memory::{active_level_4_table, translate_addr, BootInfoFrameAllocator};

#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
    println!("{}", info);
    loop {}
}


entry_point!(kernel_main);

fn kernel_main(boot_info: &'static BootInfo) -> ! {
    println!("Hello World{}", "!");

    blog_os::init(); // new

    // use x86_64::registers::control::Cr3;
    //
    // let (level_4_page_table, _) = Cr3::read();
    // println!("Level 4 page table at: {:?}", level_4_page_table.start_address());

    let phys_mem_offset = VirtAddr::new(boot_info.physical_memory_offset);
    // new: initialize a mapper
    let mut mapper = unsafe { memory::init(phys_mem_offset) };

    let mut frame_allocator = unsafe {
        BootInfoFrameAllocator::init(&boot_info.memory_map)
    };

    // 映射未使用的页
    let page = Page::containing_address(VirtAddr::new(0xdeadbeaf000));
    memory::create_example_mapping(page, &mut mapper, &mut frame_allocator);

    // 通过新的映射将字符串 `New!`  写到屏幕上。
    let page_ptr: *mut u64 = page.start_address().as_mut_ptr();
    unsafe { page_ptr.offset(400).write_volatile(0x_f021_f077_f065_f04e)};

    // new
    allocator::init_heap(&mut mapper, &mut frame_allocator)
        .expect("heap initialization failed");

    // let addresses = [
    //     // the identity-mapped vga buffer page
    //     0xb8000,
    //     // some code page
    //     0x201008,
    //     // some stack page
    //     0x0100_0020_1a10,
    //     // virtual address mapped to physical address 0
    //     boot_info.physical_memory_offset,
    // ];
    //
    // for &address in &addresses {
    //     let virt = VirtAddr::new(address);
    //     // new: use the `mapper.translate_addr` method
    //     let phys = mapper.translate_addr(virt);
    //     println!("{:?} -> {:?}", virt, phys);
    // }

    // let x = Box::new(41);

    // allocate a number on the heap
    let heap_value = Box::new(41);
    println!("heap_value at {:p}", heap_value);

    // create a dynamically sized vector
    let mut vec = Vec::new();
    for i in 0..500 {
        vec.push(i);
    }
    println!("vec at {:p}", vec.as_slice());

    // create a reference counted vector -> will be freed when count reaches 0
    let reference_counted = Rc::new(vec![1, 2, 3]);
    let cloned_reference = reference_counted.clone();
    println!("current reference count is {}", Rc::strong_count(&cloned_reference));
    core::mem::drop(reference_counted);
    println!("reference count is {} now", Rc::strong_count(&cloned_reference));

    println!("It did not crash!");
    blog_os::hlt_loop();
}
// #[unsafe(no_mangle)]
// pub extern "C" fn _start() -> ! {



    //
    // // invoke a breakpoint exception
    // x86_64::instructions::interrupts::int3(); // new


    // trigger a page fault
    // unsafe {
    //     *(0xdeadbeef as *mut u8) = 42;
    // };

    // fn stack_overflow() {
    //     stack_overflow(); // 每一次递归都会将返回地址入栈
    // }

    // 触发 stack overflow
    // stack_overflow();

    // println!("you still alive!!!");

    // new
    // let ptr = 0xdeadbeaf as *mut u8;
    // unsafe { *ptr = 42; }


    // Note: The actual address might be different for you. Use the address that
    // your page fault handler reports.
    // let ptr = 0x205eb9 as *mut u8;
    //
    // // read from a code page
    // unsafe { let x = *ptr; }
    // println!("read worked");
    //
    // // write to a code page
    // unsafe { *ptr = 42; }
    // println!("write worked");


// }


